home *** CD-ROM | disk | FTP | other *** search
/ Sun Solutions 1997 April to September / Sun Solutions CD - APR '97 - SEP '97 (704-3778-12 Rev. H)(Sun Microsystems, Inc.)(1997).iso / products / Hyperion / src / cdinfo.c < prev    next >
C/C++ Source or Header  |  1997-02-26  |  18KB  |  858 lines

  1. /*
  2.  * @(#)cdinfo.c    1.85    12/18/93
  3.  *
  4.  * Get information about a CD.
  5.  */
  6. static char *ident = "@(#)cdinfo.c    1.85 12/18/93";
  7.  
  8. #include <errno.h>
  9. #include <stdio.h>
  10. #include <sys/types.h>
  11. #include "struct.h"
  12.  
  13. void *calloc(), *malloc(), *realloc(), print_cdinfo(), wipe_cdinfo();
  14. char *strchr(), *getenv();
  15.  
  16. struct play *playlist = NULL;
  17. struct cdinfo_wm thiscd, *cd = &thiscd;
  18.  
  19. int    cur_track = -1;    /* Current track number, starting at 1 */
  20. int    cur_index = 0;    /* Current index mark */
  21. int    cur_lasttrack = 999;    /* Last track to play in current chunk */
  22. int    cur_firsttrack = 0;    /* First track of current chunk */
  23. int    cur_pos_abs;    /* Current absolute position in seconds */
  24. int    cur_frame;    /* Current frame number */
  25. int    cur_pos_rel;    /* Current track-relative position in seconds */
  26. int    cur_tracklen;    /* Length in seconds of current track */
  27. int    cur_cdlen;    /* Length in seconds of entire CD */
  28. int    cur_ntracks;    /* Number of tracks on CD (= tracks + sections) */
  29. int    cur_nsections;    /* Number of sections currently defined */
  30. enum cd_modes    cur_cdmode = EJECTED;
  31. int    cur_listno;    /* Current index into the play list, if playing */
  32. char *    cur_artist;    /* Name of current CD's artist */
  33. char *    cur_cdname;    /* Album name */
  34. char *    cur_trackname;    /* Take a guess */
  35. char    cur_contd;    /* Continued flag */
  36. char    cur_avoid;    /* Avoid flag */
  37.  
  38. int    exit_on_eject = 0;
  39.  
  40. extern int cur_stopmode;
  41. extern int info_modified;
  42. extern int big_spaces;
  43.  
  44. /*
  45.  * insert_trackinfo()
  46.  *
  47.  * Add a new track to the CD info structure.  Pass the position of the new
  48.  * entry in the track list -- 0 will make this the first track, 1 the second,
  49.  * etc.  The new entry will be zeroed out.
  50.  */
  51. void
  52. insert_trackinfo(num)
  53.     int    num;
  54. {
  55.     struct trackinfo *newtrk;
  56.  
  57.     /* Easy case: the list is empty */
  58.     if (cd->trk == NULL)
  59.         if ((cd->trk = (struct trackinfo *) calloc(1,
  60.                         sizeof(*newtrk))) == NULL)
  61.         {
  62. nomem:
  63.             perror("insert_trackinfo");
  64.             exit(1);
  65.         }
  66.         else
  67.             return;
  68.  
  69.     /* Stick the new entry in cd->trk[]. */
  70.     if ((newtrk = (struct trackinfo *) malloc(sizeof(*newtrk) *
  71.                         (cur_ntracks + 1))) == NULL)
  72.         goto nomem;
  73.  
  74.     if (num)
  75.         memcpy(newtrk, cd->trk, sizeof(*newtrk) * num);
  76.     memset(&newtrk[num], 0, sizeof(*newtrk));
  77.     if (num < cur_ntracks)
  78.         memcpy(&newtrk[num + 1], &cd->trk[num], sizeof(*newtrk) *
  79.             (cur_ntracks - num));
  80.  
  81.     free(cd->trk);
  82.     cd->trk = newtrk;
  83. }
  84.  
  85. /*
  86.  * split_trackinfo()
  87.  *
  88.  * Split a track in two at a particular position (absolute, in frames).  All
  89.  * internal data structures and variables will be adjusted to the new
  90.  * numbering scheme.  Pass in the track number (>=1) to split, which is also
  91.  * the index into cd->trk[] of the new entry.
  92.  *
  93.  * If pos is within 1 second of the start of another track, the split fails.
  94.  *
  95.  * Returns 1 on success, 0 if the track couldn't be inserted.
  96.  *
  97.  * Note: updating user interface elements is up to the caller.
  98.  */
  99. split_trackinfo(pos)
  100.     int    pos;
  101. {
  102.     int    i, l, num;
  103.  
  104.     if (pos < cd->trk[0].start)
  105.         return (0);
  106.  
  107.     /* First find the appropriate track. */
  108.     for (num = 0; num < cur_ntracks; num++)
  109.         if (cd->trk[num].start - 75 < pos &&
  110.                         cd->trk[num].start + 75 > pos)
  111.             return (0);
  112.         else if (cd->trk[num].start > pos)
  113.             break;
  114.     if (num == 0)
  115.         return (0);
  116.  
  117.     /* Insert the new entry into the track array. */
  118.     insert_trackinfo(num);
  119.  
  120.     /* Update the easy variables. */
  121.     if (cur_track > num)
  122.         cur_track++;
  123.     if (cur_firsttrack > num)
  124.         cur_firsttrack++;
  125.     if (cur_lasttrack > num)
  126.         cur_lasttrack++;
  127.  
  128.     /* Update the user-defined playlists. */
  129.     if (cd->lists != NULL)
  130.         for (l = 0; cd->lists[l].name != NULL; l++)
  131.             if (cd->lists[l].list != NULL)
  132.                 for (i = 0; cd->lists[l].list[i]; i++)
  133.                     if (cd->lists[l].list[i] > num)
  134.                         cd->lists[l].list[i]++;
  135.  
  136.     /* Update the internal playlist. */
  137.     if (playlist != NULL)
  138.         for (i = 0; playlist[i].start; i++)
  139.         {
  140.             if (playlist[i].start > num)
  141.                 playlist[i].start++;
  142.             if (playlist[i].end > num)
  143.                 playlist[i].end++;
  144.         }
  145.     
  146.     /* Now adjust the information in cd->trk[]. */
  147.     cd->trk[num].start = pos;
  148.     if (num == cur_ntracks)
  149.         cd->trk[num].length = cur_cdlen - pos / 75;
  150.     else
  151.         cd->trk[num].length = (cd->trk[num + 1].start - pos) / 75;
  152.     cd->trk[num - 1].length -= cd->trk[num].length;
  153.     if (cur_track == num)
  154.         cur_tracklen -= cd->trk[num].length;
  155.     cd->trk[num].track = cd->trk[num - 1].track;
  156.     cd->trk[num].data = cd->trk[num - 1].data;
  157.     cd->trk[num].contd = 1;
  158.     cd->trk[num].volume = cd->trk[num - 1].volume;
  159.  
  160.     if (cd->trk[num - 1].section == 0)
  161.         cd->trk[num - 1].section = 1;
  162.     cd->trk[num].section = cd->trk[num - 1].section + 1;
  163.  
  164.     cur_ntracks++;
  165.     cur_nsections++;
  166.  
  167.     for (i = num + 1; i < cur_ntracks; i++)
  168.         if (cd->trk[i].track == cd->trk[num].track)
  169.             cd->trk[i].section++;
  170.     
  171.     return (1);
  172. }
  173.  
  174. /*
  175.  * remove_trackinfo()
  176.  *
  177.  * Remove a track's internal data.  This is similar to split_trackinfo()
  178.  * above, but simpler.  A track's initial section can't be removed.  Track
  179.  * numbers start at 0.
  180.  *
  181.  * Returns 1 on success, 0 on failure.
  182.  */
  183. remove_trackinfo(num)
  184.     int    num;
  185. {
  186.     int    i, l;
  187.  
  188.     if (num < 1 || num >= cur_ntracks || cd->trk[num].section < 2)
  189.         return (0);
  190.     
  191.     cd->trk[num - 1].length += cd->trk[num].length;
  192.  
  193.     for (i = num; i < cur_ntracks - 1; i++)
  194.         memcpy(&cd->trk[i], &cd->trk[i + 1], sizeof(cd->trk[0]));
  195.  
  196.     if (cur_track > num)
  197.         cur_track--;
  198.     if (cur_firsttrack > num)
  199.         cur_firsttrack--;
  200.     if (cur_lasttrack > num)
  201.         cur_lasttrack--;
  202.     
  203.     /* Update the user-defined playlists. */
  204.     if (cd->lists != NULL)
  205.         for (l = 0; cd->lists[l].name != NULL; l++)
  206.             if (cd->lists[l].list != NULL)
  207.                 for (i = 0; cd->lists[l].list[i]; i++)
  208.                     if (cd->lists[l].list[i] > num)
  209.                         cd->lists[l].list[i]--;
  210.     
  211.     /* Update the internal playlist. */
  212.     if (playlist != NULL)
  213.         for (i = 0; playlist[i].start; i++)
  214.         {
  215.             if (playlist[i].start > num)
  216.                 playlist[i].start--;
  217.             if (playlist[i].end > num)
  218.                 playlist[i].end--;
  219.         }
  220.     
  221.     cur_ntracks--;
  222.     cur_nsections--;
  223.  
  224.     /*
  225.      * Update the section numbers for this track.  If this is the only
  226.      * user-created section in a track, get rid of the section number
  227.      * in the track's entry.
  228.      */
  229.     if (num == cur_ntracks || cd->trk[num - 1].track != cd->trk[num].track)
  230.     {
  231.         if (cd->trk[num - 1].section == 1)
  232.             cd->trk[num - 1].section = 0;
  233.     }
  234.     else
  235.         for (i = num; i < cur_ntracks; i++)
  236.             if (cd->trk[i].track == cd->trk[num - 1].track)
  237.                 cd->trk[i].section--;
  238.  
  239.     return (1);
  240. }
  241.  
  242. /*
  243.  * listentry()
  244.  *
  245.  * Return a scrolling list entry.
  246.  */
  247. char *
  248. listentry(num)
  249.     int    num;
  250. {
  251.     static char    buf[600];
  252.     char        *name, tracknum[20];
  253.     int        digits;
  254.     int        sdigits;
  255.  
  256.     if (num >= 0 && num < cur_ntracks)
  257.     {
  258.         if (big_spaces)
  259.         {
  260.             digits = 2;
  261.             sdigits = cur_nsections < 9 ? -1 : -2;
  262.         }
  263.         else
  264.         {
  265.             digits = cd->trk[num].track < 10 ? 3 : 2;
  266.             sdigits = cur_nsections < 9 ? -1 : -3;
  267.         }
  268.         name = cd->trk[num].songname ? cd->trk[num].songname : "";
  269.  
  270.         if (cur_nsections)
  271.             if (cd->trk[num].section > 9)
  272.                 sprintf(tracknum, "%*d.%d", digits,
  273.                     cd->trk[num].track,
  274.                     cd->trk[num].section);
  275.             else if (cd->trk[num].section)
  276.                 sprintf(tracknum, "%*d.%*d", digits,
  277.                     cd->trk[num].track, sdigits,
  278.                     cd->trk[num].section);
  279.             else
  280.                 sprintf(tracknum, "%*d%*s", digits,
  281.                     cd->trk[num].track,
  282.                     2 - sdigits - big_spaces, " ");
  283.         else
  284.             sprintf(tracknum, "%*d", digits, cd->trk[num].track);
  285.  
  286.         if (cd->trk[num].data)
  287.             sprintf(buf, "%s) %3dMB %s", tracknum,
  288.                 cd->trk[num].length / 1024, name);
  289.         else
  290.             sprintf(buf, "%s) %02d:%02d %s", tracknum,
  291.                 cd->trk[num].length / 60,
  292.                 cd->trk[num].length % 60, name);
  293.  
  294.         return (buf);
  295.     }
  296.     else
  297.         return (NULL);
  298. }
  299.  
  300. /*
  301.  * trackname()
  302.  *
  303.  * Return a track's name.
  304.  */
  305. char *
  306. trackname(num)
  307.     int    num;
  308. {
  309.     if (num >= 0 && num < cur_ntracks)
  310.         if (cd->trk[num].songname)
  311.             return (cd->trk[num].songname);
  312.         else
  313.             return ("");
  314.     else
  315.         return (NULL);
  316. }
  317.  
  318. /*
  319.  * tracklen()
  320.  *
  321.  * Return a track's length in seconds.
  322.  */
  323. tracklen(num)
  324.     int    num;
  325. {
  326.     if (cd != NULL && num >= 0 && num < cur_ntracks)
  327.         return (cd->trk[num].length);
  328.     else
  329.         return (0);
  330. }
  331.  
  332. /*
  333.  * get_default_volume()
  334.  *
  335.  * Return the default volume (0-32, 0=none) for the CD or a track.
  336.  */
  337. get_default_volume(track)
  338.     int    track;
  339. {
  340.     if (! track)
  341.         return (cd->volume);
  342.     else if (track <= cur_ntracks)
  343.         return (cd->trk[track - 1].volume);
  344.     else
  345.         return (0);
  346. }
  347.  
  348. /*
  349.  * get_contd()
  350.  *
  351.  * Return the contd value for a track.
  352.  */
  353. get_contd(num)
  354.     int    num;
  355. {
  356.     if (num >= 0 && num < cur_ntracks)
  357.         return (cd->trk[num].contd);
  358.     else
  359.         return (0);
  360. }
  361.  
  362. /*
  363.  * get_avoid()
  364.  *
  365.  * Return the avoid value for a track.
  366.  */
  367. get_avoid(num)
  368.     int    num;
  369. {
  370.     if (num >= 0 && num < cur_ntracks)
  371.         return (cd->trk[num].avoid);
  372.     else
  373.         return (0);
  374. }
  375.  
  376. /*
  377.  * get_autoplay()
  378.  *
  379.  * Is autoplay set on this disc?
  380.  */
  381. get_autoplay()
  382. {
  383.     return (cd->autoplay);
  384. }
  385.  
  386. /*
  387.  * get_playmode()
  388.  *
  389.  * Return the default playmode for the CD.
  390.  */
  391. get_playmode()
  392. {
  393.     return (cd->playmode);
  394. }
  395.  
  396. /*
  397.  * get_runtime()
  398.  *
  399.  * Return the total running time for the current playlist in seconds.
  400.  */
  401. get_runtime()
  402. {
  403.     int    i;
  404.  
  405.     if (playlist == NULL || playlist[0].start == 0 || cur_firsttrack == -1)
  406.         return (cd == NULL ? 0 : cd->length);
  407.  
  408.     for (i = 0; playlist[i].start; i++)
  409.         ;
  410.  
  411.     return (playlist[i].starttime);
  412. }
  413.  
  414. /*
  415.  * default_volume()
  416.  *
  417.  * Set the default volume for the CD or a track.
  418.  */
  419. void
  420. default_volume(track, vol)
  421.     int    track, vol;
  422. {
  423.     if (track == 0)
  424.         cd->volume = vol;
  425.     else if (track <= cur_ntracks)
  426.         cd->trk[track - 1].volume = vol;
  427. }
  428.  
  429. /*
  430.  * Play the next thing on the playlist, if any.
  431.  */
  432. void
  433. play_next_entry()
  434. {
  435.     if (cd == NULL)
  436.         return;
  437.     if (playlist != NULL && playlist[cur_listno].start)
  438.     {
  439.         play_cd(playlist[cur_listno].start, 0,
  440.             playlist[cur_listno].end);
  441.         cur_listno++;
  442.     }
  443.     else
  444.         stop_cd();
  445. }
  446.  
  447. /*
  448.  * Play the next track, following playlists as necessary.
  449.  */
  450. void
  451. play_next_track()
  452. {
  453.     if (cd == NULL)
  454.         return;
  455.  
  456.     /* Is the current playlist entry done?  Move on, if so. */
  457.     if (playlist == NULL || cur_track + 1 == playlist[cur_listno - 1].end)
  458.         play_next_entry();
  459.     else
  460.         play_cd(cur_track + 1, 0, playlist[cur_listno - 1].end);
  461. }
  462.  
  463. /*
  464.  * Play the previous track, hopping around the playlist as necessary.
  465.  */
  466. void
  467. play_prev_track()
  468. {
  469.     if (cd == NULL)
  470.         return;
  471.  
  472.     if (playlist == NULL)
  473.         return;
  474.  
  475.     /* If we're in the middle of this playlist entry, go back one track */
  476.     if (cur_track > playlist[cur_listno - 1].start)
  477.         play_cd(cur_track - 1, 0, playlist[cur_listno - 1].end);
  478.     else
  479.         if (cur_listno > 1)
  480.         {
  481.             cur_listno--;
  482.             play_cd(playlist[cur_listno - 1].end - 1, 0,
  483.                 playlist[cur_listno - 1].end);
  484.         }
  485.         else
  486.             play_cd(playlist[0].start, 0, playlist[0].end);
  487. }
  488.  
  489. /*
  490.  * stash_cdinfo(artist, cdname)
  491.  */
  492. void
  493. stash_cdinfo(artist, cdname, autoplay, playmode)
  494.     char    *artist, *cdname;
  495.     int    autoplay, playmode;
  496. {
  497.     if (cd != NULL)
  498.     {
  499.         if (strcmp(cd->artist, artist))
  500.             info_modified = 1;
  501.         strcpy(cd->artist, artist);
  502.  
  503.         if (strcmp(cd->cdname, cdname))
  504.             info_modified = 1;
  505.         strcpy(cd->cdname, cdname);
  506.  
  507.         if (!!cd->autoplay != !!autoplay)
  508.             info_modified = 1;
  509.         cd->autoplay = autoplay;
  510.  
  511.         if (!!cd->playmode != !!playmode)
  512.             info_modified = 1;
  513.         cd->playmode = playmode;
  514.     }
  515. }
  516.  
  517. /* Free some memory and set a pointer to null. */
  518. void
  519. freeup(x)
  520. void **x;
  521. {
  522.     if (*x != NULL)
  523.     {
  524.         free(*x);
  525.         *x = NULL;
  526.     }
  527. }
  528.  
  529. /*
  530.  * wipe_cdinfo()
  531.  *
  532.  * Clear out all a CD's soft information (presumably in preparation for
  533.  * reloading from the database.)
  534.  */
  535. void
  536. wipe_cdinfo()
  537. {
  538.     struct playlist    *l;
  539.     int        i;
  540.  
  541.     if (cd != NULL)
  542.     {
  543.         cd->artist[0] = cd->cdname[0] = '\0';
  544.         cd->autoplay = cd->playmode = cd->volume = 0;
  545.         cd->whichdb = NULL;
  546.         freeup(&cd->otherrc);
  547.         freeup(&cd->otherdb);
  548.  
  549.         if (thiscd.lists != NULL)
  550.         {
  551.             for (l = thiscd.lists; l->name != NULL; l++)
  552.             {
  553.                 free(l->name);
  554.                 free(l->list);
  555.             }
  556.             freeup(&thiscd.lists);
  557.         }
  558.  
  559.         for (i = 0; i < cur_ntracks; i++)
  560.         {
  561.             freeup(&cd->trk[i].songname);
  562.             freeup(&cd->trk[i].otherrc);
  563.             freeup(&cd->trk[i].otherdb);
  564.             cd->trk[i].avoid = cd->trk[i].contd = 0;
  565.             cd->trk[i].volume = 0;
  566.             if (cd->trk[i].section > 1)
  567.                 remove_trackinfo(i--);
  568.         }
  569.     }
  570. }
  571.  
  572. /*
  573.  * stash_trkinfo(track, songname, contd, avoid)
  574.  *
  575.  * Update information about a track on the current CD.
  576.  */
  577. void
  578. stash_trkinfo(track, songname, contd, avoid)
  579.     int    track, contd, avoid;
  580.     char    *songname;
  581. {
  582.     if (cd != NULL)
  583.     {
  584.         track--;
  585.         if (!!cd->trk[track].contd != !!contd)
  586.             info_modified = 1;
  587.         cd->trk[track].contd = track ? contd : 0;
  588.  
  589.         if (!!cd->trk[track].avoid != !!avoid)
  590.             info_modified = 1;
  591.         cd->trk[track].avoid = avoid;
  592.  
  593.         if ((cd->trk[track].songname == NULL && songname[0]) ||
  594.                 (cd->trk[track].songname != NULL &&
  595.                 strcmp(cd->trk[track].songname, songname)))
  596.         {
  597.             info_modified = 1;
  598.             strmcpy(&cd->trk[track].songname, songname);
  599.         }
  600.     }
  601. }
  602.  
  603. /*
  604.  * new_list()
  605.  *
  606.  * Add a playlist to a CD.
  607.  */
  608. struct playlist *
  609. new_list(cd, listname)
  610.     struct cdinfo_wm    *cd;
  611.     char        *listname;
  612. {
  613.     int    nlists = 0;
  614.     struct playlist *l;
  615.  
  616.     if (cd->lists != NULL)
  617.     {
  618.         for (nlists = 0; cd->lists[nlists].name != NULL; nlists++)
  619.             ;
  620.         l = (struct playlist *)realloc(cd->lists, (nlists + 2) *
  621.             sizeof (struct playlist));
  622.     }
  623.     else
  624.         l = (struct playlist *)malloc(2 * sizeof (struct playlist));
  625.  
  626.     if (l == NULL)
  627.         return (NULL);
  628.  
  629.     l[nlists + 1].name = NULL;
  630.     l[nlists].name = NULL;        /* so strmcpy doesn't free() it */
  631.     strmcpy(&l[nlists].name, listname);
  632.     l[nlists].list = NULL;
  633.     cd->lists = l;
  634.  
  635.     return (&l[nlists]);
  636. }
  637.  
  638. /*
  639.  * make_playlist()
  640.  *
  641.  * Construct a playlist for the current CD.  If we're in shuffle mode, play
  642.  * each non-avoided track once, keeping continued tracks in the right order.
  643.  *
  644.  * If playmode is 2, use playlist number (playmode-2).  XXX should do
  645.  * bounds checking on this, probably.
  646.  *
  647.  * If consecutive tracks are being played, only make one playlist entry for
  648.  * them, so the CD player won't pause between tracks while we wake up.
  649.  */
  650. void
  651. make_playlist(playmode, starttrack)
  652.     int    playmode, starttrack;
  653. {
  654.     int    i, avoiding = 1, entry = 0, count, track,
  655.         *thislist;
  656.  
  657.     cur_listno = 0;
  658.     if (playlist != NULL)
  659.         free(playlist);
  660.     playlist = malloc(sizeof (*playlist) * (cur_ntracks + 1));
  661.     if (playlist == NULL)
  662.     {
  663.         perror("playlist");
  664.         exit(1);
  665.     }
  666.  
  667.     /* If this is a data-only CD, we can't play it. */
  668.     if ((starttrack && cd->trk[starttrack - 1].data) ||
  669.         (cur_ntracks == 1 && cd->trk[0].data))
  670.     {
  671.         playlist[0].start = 0;
  672.         playlist[0].end = 0;
  673.         playlist[1].start = 0;
  674.         return;
  675.     }
  676.  
  677.     if (playmode == 1)
  678.     {
  679.         char *done = malloc(cur_ntracks);
  680.  
  681.         if (done == NULL)
  682.         {
  683.             perror("randomizer");
  684.             exit(1);
  685.         }
  686.  
  687.         count = cur_ntracks;
  688.         if (starttrack && cd->trk[starttrack - 1].avoid)
  689.             count++;
  690.         for (i = 0; i < cur_ntracks; i++)
  691.             if (cd->trk[i].contd || cd->trk[i].avoid ||
  692.                 cd->trk[i].data)
  693.             {
  694.                 done[i] = 1;
  695.                 count--;
  696.             }
  697.             else
  698.                 done[i] = 0;
  699.  
  700.         for (i = 0; i < count; i++)
  701.         {
  702.             int end;    /* for readability */
  703.             if (starttrack)
  704.             {
  705.                 track = starttrack - 1;
  706.                 starttrack = 0;
  707.             }
  708.             else
  709.                 while (done[track = rand() % cur_ntracks])
  710.                     ;
  711.  
  712.             playlist[i].start = track + 1;
  713.  
  714.             /* play all subsequent continuation tracks too */
  715.             for (end = track + 1; end < cur_ntracks + 1; end++)
  716.                 if (! cd->trk[end].contd ||
  717.                         cd->trk[end].avoid ||
  718.                         cd->trk[end].data)
  719.                     break;
  720.             playlist[i].end = end + 1;
  721.  
  722.             done[track]++;
  723.         }
  724.         playlist[i].start = 0;
  725.  
  726.         free(done);
  727.     }
  728.     else if (playmode >= 2 && cd->lists && cd->lists[playmode - 2].name)
  729.     {
  730.         count = 2;    /* one terminating entry, and one for start */
  731.         thislist = cd->lists[playmode - 2].list;
  732.  
  733.         for (i = 0; thislist[i]; i++)
  734.             if (thislist[i + 1] != thislist[i] + 1)
  735.                 count++;
  736.  
  737.         if (playlist != NULL)
  738.             free(playlist);
  739.         playlist = malloc(sizeof (*playlist) * count);
  740.         if (playlist == NULL)
  741.         {
  742.             perror("playlist");
  743.             exit(1);
  744.         }
  745.  
  746.         count = 0;
  747.         if (starttrack)
  748.         {
  749.             playlist[0].start = starttrack;
  750.             for (track = 0; thislist[track]; track++)
  751.                 if (starttrack == thislist[track])
  752.                     break;
  753.             if (! thislist[track])
  754.             {
  755.                 playlist[0].end = starttrack + 1;
  756.                 playlist[1].start = thislist[0];
  757.                 count = 1;
  758.                 track = 0;
  759.             }
  760.         }
  761.         else
  762.         {
  763.             playlist[0].start = thislist[0];
  764.             track = 0;
  765.         }
  766.  
  767.         for (i = track; thislist[i]; i++)
  768.             if (thislist[i + 1] != thislist[i] + 1)
  769.             {
  770.                 playlist[count].end = thislist[i] + 1;
  771.                 count++;
  772.                 playlist[count].start = thislist[i + 1];
  773.             }
  774.     }
  775.     else
  776.     {
  777.         for (i = starttrack ? starttrack - 1 : 0; i < cur_ntracks; i++)
  778.             if (avoiding && ! (cd->trk[i].avoid || cd->trk[i].data))
  779.             {
  780.                 playlist[entry].start = i + 1;
  781.                 avoiding = 0;
  782.             }
  783.             else if (! avoiding && (cd->trk[i].avoid ||
  784.                         cd->trk[i].data))
  785.             {
  786.                 playlist[entry].end = i + 1;
  787.                 avoiding = 1;
  788.                 entry++;
  789.             }
  790.         if (! avoiding)
  791.             playlist[entry].end = i + 1;
  792.         playlist[entry + !avoiding].start = 0;
  793.     }
  794.  
  795.     /*
  796.      * Now go through the list, whatever its source, and figure out
  797.      * cumulative starting times for each entry.
  798.      */
  799.     entry = count = 0;
  800.     do {
  801.         playlist[entry].starttime = count;
  802.  
  803.         if (playlist[entry].start)
  804.             for (i = playlist[entry].start; i <
  805.                         playlist[entry].end; i++)
  806.                 count += cd->trk[i - 1].length;
  807.     } while (playlist[entry++].start);
  808. }
  809.  
  810. /*
  811.  * Find a particular track's location in the current playlist.  Sets the
  812.  * appropriate variables (cur_listno, cur_firsttrack, cur_lasttrack).
  813.  */
  814. void
  815. pl_find_track(track)
  816.     int    track;
  817. {
  818.     int    i;
  819.  
  820.     if (playlist == NULL)
  821.     {
  822.         fprintf(stderr, "Null playlist!  Huh?\n");
  823.         return;
  824.     }
  825.  
  826.     for (i = 0; playlist[i].start; i++)
  827.         if (track >= playlist[i].start && track < playlist[i].end)
  828.         {
  829.             cur_listno = i + 1;
  830.             cur_firsttrack = playlist[i].start;
  831.             cur_lasttrack = playlist[i].end - 1;
  832.             return;
  833.         }
  834.     
  835.     /*
  836.      * Couldn't find the track in question.  Make a special entry with
  837.      * just that track.
  838.      */
  839.     if (! playlist[i].start)
  840.     {
  841.         playlist = realloc(playlist, (i + 2) * sizeof(*playlist));
  842.         if (playlist == NULL)
  843.         {
  844.             perror("playlist realloc");
  845.             exit(1);
  846.         }
  847.  
  848.         playlist[i + 1].start = playlist[i + 1].end = 0;
  849.         playlist[i + 1].starttime = playlist[i].starttime +
  850.             cd->trk[track - 1].length;
  851.         playlist[i].start = track;
  852.         playlist[i].end = track + 1;
  853.         cur_listno = i + 1;
  854.         cur_firsttrack = track;
  855.         cur_lasttrack = track;
  856.     }
  857. }
  858.